/*!
 * @file  XYXKC_K210.cpp
 * @brief mind module for k210 visual module
 * @author xyxedu
 * @date 2014-4-12
 * @version 1.0.0
 */

#include "XYXKC_K210.h"
#include "MyModbusCRC.h"
XYXKC_K210::XYXKC_K210():_k210_Serial() {
    // 构造函数

}
XYXKC_K210::~XYXKC_K210() {
}
void XYXKC_K210::begin(SoftwareSerial *serial){
    _k210_Serial.begin(serial,BAUD_RATE);
}
void XYXKC_K210::begin(HardwareSerial *serial){
    _k210_Serial.begin(serial,BAUD_RATE);
}
void XYXKC_K210::begin(HardwareSerial *serial,int rxPin,int txPin){
    _k210_Serial.begin(serial,rxPin,txPin,BAUD_RATE);

}

void XYXKC_K210::retrieveDataOnce() {
        FrameIndex uartIndex = HEADER1_INDEX;
        vector<uint8_t> v;
        while (_k210_Serial.available()) {
            uint8_t incomingByte = _k210_Serial.read();

            // 检查帧头
            if (uartIndex == HEADER1_INDEX && incomingByte == FIRST_FRAME_HEADER) {
                uartIndex = HEADER2_INDEX;
            } else if (uartIndex == HEADER2_INDEX && incomingByte == SECOND_FRAME_HEADER) {
                uartIndex = ALGORITHM_ID_INDEX;
            } else if (uartIndex == ALGORITHM_ID_INDEX) {
                v.push_back(incomingByte);
                uartIndex = DATA_INDEX;
            } else if (uartIndex == DATA_INDEX) {
                    v.push_back(incomingByte);
                    for (uint8_t i = 0; i < 7;i++){
                        v.push_back(_k210_Serial.read());
                    }
                    uint8_t len = _k210_Serial.read();
                    v.push_back(len);
                    for (uint8_t i = 0; i < len;i++){
                        if(_k210_Serial.available()){
                            v.push_back(_k210_Serial.read());
                        }
                    }
                    uartIndex = CRC_INDEX;

            } else if(uartIndex == CRC_INDEX){
                //crc检验
                uint16_t crcReceived = incomingByte;
                crcReceived |= (uint16_t) _k210_Serial.read() << 8;
                uint16_t crcCalculated = MyModbusCRC::calculate(v);

                if (crcCalculated == crcReceived) {

                    _data.fun = v[0];
                    _data.x = (v[1] | (v[2] << 8));
                    _data.y = (v[3] | (v[4] << 8));
                    _data.w = (v[5] | (v[6] << 8));
                    _data.h = (v[7] | (v[8] << 8));
                    _data.msg = "";
                    for (int i = 0; i < v[9]; i++){
                        _data.msg += (char) v[10+i];
                    }
                    _data.isNewData = true;

                }
                uartIndex = END_INDEX;

            }

        }
}
bool XYXKC_K210::parsingData(enum K210_FUNCTION_ENUM tag, K210FunMSG &funData) {
    if (_data.fun!= tag || (!_data.isNewData)) {
        return false;
    }
    funData.x = _data.x;
    funData.y = _data.y;
    funData.w = _data.w;
    funData.h = _data.h;
    funData.msg = _data.msg;
    _data.isNewData = false;
    return true;
}

void XYXKC_K210::algorithmSwitching(enum K210_FUNCTION_ENUM tag) {
    vector<uint8_t> v;
    v.push_back(CHANGE);
    v.push_back(ALGORITHM_NUMBER);
    v.push_back(tag);
    uint16_t crcCalculated = MyModbusCRC::calculate(v);
    unsigned int time = 0;
    while (1){
        if(millis() - time >= 500){
            time = millis();
            _k210_Serial.write(FIRST_FRAME_HEADER);
            _k210_Serial.write(SECOND_FRAME_HEADER);
            _k210_Serial.write(v[0]);
            _k210_Serial.write(v[1]);
            _k210_Serial.write(v[2]);
            _k210_Serial.write(crcCalculated & 0xFF);
            _k210_Serial.write(crcCalculated >> 8 & 0xFF);
        }
        retrieveDataOnce();
        if (_data.fun == K210_FUNCTION_ENUM::ai_zero &&_data.msg == "Y"){
            break;
        }
    }
    _data.msg = "";
}

void XYXKC_K210::fillInLight(enum CHANGE_ENUM tag,  bool value) {
    vector<uint8_t> v;
    v.push_back(CHANGE);
    v.push_back(tag);
    v.push_back(value);
    uint16_t crcCalculated = MyModbusCRC::calculate(v);
    _k210_Serial.write(FIRST_FRAME_HEADER);
    _k210_Serial.write(SECOND_FRAME_HEADER);
    _k210_Serial.write(v[0]);
    _k210_Serial.write(v[1]);
    _k210_Serial.write(v[2]);
    _k210_Serial.write(crcCalculated & 0xFF);
    _k210_Serial.write(crcCalculated >> 8 & 0xFF);

}
void XYXKC_K210::saveImage() {
    vector<uint8_t> v;
    v.push_back(INCREASE);
    v.push_back(0x01);
    v.push_back(0);
    uint16_t crcCalculated = MyModbusCRC::calculate(v);
    _k210_Serial.write(FIRST_FRAME_HEADER);
    _k210_Serial.write(SECOND_FRAME_HEADER);
    _k210_Serial.write(v[0]);
    _k210_Serial.write(v[1]);
    _k210_Serial.write(v[2]);
    _k210_Serial.write(crcCalculated & 0xFF);
    _k210_Serial.write(crcCalculated >> 8 & 0xFF);
}
void XYXKC_K210::getImageBase64() {
    uint8_t base64Index = 1;
    vector<uint8_t> v;
    v.push_back(INCREASE);
    v.push_back(0x02);
    v.push_back(base64Index);
    uint16_t crcCalculated = MyModbusCRC::calculate(v);
    unsigned int time = 0;
    _imageBase64 = "";
    while (1){
        if(millis() - time >= 500){
            time = millis();
            _k210_Serial.write(FIRST_FRAME_HEADER);
            _k210_Serial.write(SECOND_FRAME_HEADER);
            _k210_Serial.write(v[0]);
            _k210_Serial.write(v[1]);
            _k210_Serial.write(v[2]);
            _k210_Serial.write(crcCalculated & 0xFF);
            _k210_Serial.write(crcCalculated >> 8 & 0xFF);
        }
        retrieveDataOnce();
        if (_data.fun == K210_FUNCTION_ENUM::ai_zero &&_data.w == 1 && _data.h == 1 && _data.x == base64Index){
            if (_data.x == 0) {
                break;
            }
            _imageBase64 += _data.msg;
            base64Index++;
            if(_data.x == _data.y){
                base64Index = 0;
            }
            time = 0;
            v[2] = base64Index;
            crcCalculated = MyModbusCRC::calculate(v);

        }
    }
    _data.msg = "";
}

String XYXKC_K210::getBase64(){
    return "data:image/jpg;base64,"+_imageBase64;
}